﻿/*
   Copyright [yyyy] [name of copyright owner: NG tech.]
 
  Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using SHNXml;
using System.ComponentModel;


namespace SHN
{
    class local
    {
        public readonly string str;
    }
    
    /// <summary> 
    /// Interface of net's element
    /// </summary> 
    public interface INetElement : ICloneable
    {
        /// <summary> 
        /// Return name
        /// </summary> 
        //[(DisplayNamelocal.str)]
        String Name { get; set; }
             
    }

    /// <summary> 
    /// Interface of node
    /// </summary> 
    public interface INode : INetElement
    {
        
        #region Properties

        /// <summary>
        /// set/get parents' element
        /// </summary>
        INetElement Parent { get; set; }

        /// <summary>
        /// get/set coordinate X
        /// </summary>
        Double X { get; set; }

        /// <summary>
        /// get/set coordinate Y
        /// </summary>
        Double Y { get; set; }

        /// <summary>
        /// get/set nodes' priority
        /// </summary>
        Byte Priority { get; set; }

        /// <summary>
        /// get/set color
        /// </summary>
        Color Color { get; set; }

        /// <summary>
        /// true if node is selected
        /// </summary>
        Boolean Select { get; set; }

        /// <summary>
        /// get/set radius of node
        /// </summary>
        Double Radius { get; set; }

        /// <summary>
        /// get/set marker in node
        /// </summary>
        Byte Marker { get; set; }

		/// <summary>
		/// get/set id in node
		/// </summary>
        //IntPtr id { get; set; }

		/// <summary>
		/// get/set line type in node
		/// </summary>
		SHNLineTypes LineType { get; set; }
        
        #endregion
        #region Methods

        void UnSelected();
       
        #endregion

    }

    /// <summary> 
    /// Interface of edges
    /// </summary> 
    public interface IEdge : INetElement
    {
		#region Properties

        /// <summary>
        /// set/get parents' element
        /// </summary>
		List<INetElement> Parents { get; set; }

        /// <summary>
        /// Get name of in
        /// </summary>
        String InName { get; }

        /// <summary>
        /// Get name of out
        /// </summary>
        String OutName { get; }

        Double Weight { get; set; }

        /// <summary>
        /// get/set capacity
        /// </summary>
        Int32 Capacity { get; set; }

        /// <summary>
        /// get/set color
        /// </summary>
        Color Color { get; set; }

        /// <summary>
        /// Get in
        /// </summary>
        Double MaxLength { get; set; }

        String Cost { get; set; }

		INode GetIn { get; set; }

        /// <summary>
        /// Get out
        /// </summary>
		INode GetOut { get; set; }

        /// <summary>
        /// Return true, if edge is selected
        /// </summary>
        Boolean Select { get; set; }

        /// <summary>
        /// get/set life interval
        /// </summary>
        String Interval { get; set; }

        /// <summary>
        /// Width of edge
        /// </summary>
        Double Width { get; set; }

        /// <summary>
        /// Lenght
        /// </summary>
        Double Length { get; }

        /// <summary>
        /// get/set "id in" and "id out" in edge
        /// </summary>
		/// <summary>
		//IntPtr Idblock { get; set; }

		/// <summary>
		/// get/set line type in node
		/// </summary>
		SHNLineTypes LineType { get; set; }

		//IntPtr Idtable { get; set; }
    #endregion
		#region Methods

        void AddParent(INetElement parent);

        /// <summary>
        /// return true, if edge is active
        /// </summary>
        Boolean IsEnable(Int32 i);
    #endregion
    }

    /// <summary> 
    /// Node's class. This class realize interface INode
    /// </summary> 
    public class Node : INode
    {
        #region Attribute
        String name = String.Empty;
        Byte m;  //Наличие маркера в точке
        Byte p;  //Приоритет
        Double x;
        Double y;
        Color c;
        Double R;
		SHNLineTypes currentlinetype;
        Boolean s;
        INetElement parent;
        //IntPtr ID;
		List<Edge> childedgelist = new List<Edge>();
		static public IntPtr[] linetypesID = new IntPtr[3];
        #endregion

        #region Properties
        //[Browsable(false)]
        public String Name
        {
            get { return name; }
            set { name = value; }
        }

		[Browsable(false)]
        public Double X
        {
            get { return x; }
            set { x = value; }
        }

		[Browsable(false)]
        public Double Y
        {
            get { return y; }
            set { y = value; }
        }

        public Byte Priority
        {
            get { return p; }
            set { p = value; }
        }

        public Byte Marker
        {
            get { return m; }
            set { m = value; }
        }

        public Color Color
        {
            get { return c; }
            set { c = value; }
        }

        public Boolean Select
        {
            get { return s; }
            set { s = value; }
        }

        public Double Radius
        {
            get { return R; }
            set { R = value; }
        }

		public SHNLineTypes LineType
		{
			get { return currentlinetype; }
			set { currentlinetype = value; }
		}

		//[Browsable(false)]
        public INetElement Parent
        {
            get { return parent; }
            set { parent = value; }
        }

		/*[Browsable(false)]
        public IntPtr id
        {
            get { return ID; }
            set { ID = value; }
        }*/

		public List<Edge> ChildEdgelist
		{
			get { return childedgelist; }
            set { childedgelist = value; }
        
		}
    #endregion

        public static Boolean operator <=(Node P1, Node P2)
        {
            if (P1.Priority <= P2.Priority)
                return true;
            return false;
        }

        public static Boolean operator >=(Node P1, Node P2)
        {
            if (P1.Priority >= P2.Priority)
                return true;
            return false;
        }

        #region Methods

        public Node()
        {
            
        }

        /// <summary>
        /// Create new object by <see cref="SHNXml.Node"/>
        /// </summary>
        /// <param name="node"></param>
        /// <exception cref="ArgumentException">Throw when node = null </exception>
        public Node(SHNXml.Node node)
        {
            if (node == null)
                throw new System.ArgumentException("Parameter cannot be null", "node");
            name = node.Name;
            x = node.X;
            y = node.Y;
            p = node.priority;
            Marker = node.Marker;
            Radius = node.Radius;
            LineType = (SHNLineTypes)node.LineType;
            c = Color.FromName(node.Color);
        }       

		
        public Node(Double x, Double y,Color color, Double radius)
        {
            this.x = x;
            this.y = y;
            c = color;
            R = radius;
        }
       
        public Object Clone()
        {
            Node node = new Node();
            node.Color = this.Color;
            node.Marker = this.Marker;
            node.Name = this.Name;
            node.LineType = this.LineType;
            node.Priority = this.Priority;
            node.Radius = this.Radius;
            node.Select = this.Select;
			//node.Parent = this.Parent;
            node.X = this.X;
            node.Y = this.Y;
            return node;
        }

        public void UnSelected()
        {
            Select = false;
        }

		public IntPtr GetLineTypeID()
		{
			return linetypesID[(int)LineType];
		}

        #endregion
    }

    /// <summary> 
    /// Edge's class. This class realize interface IEdge
    /// </summary> 
    public class Edge : IEdge
    {
        #region Attribute
        Double weight;
        Boolean s;
        Color c;
        INode I;                    //Вход
        INode O;                    //Выход
        String name = String.Empty;
        String interval;
        List<INetElement> parents = new List<INetElement>();
        double width;
        //IntPtr idtable;
        //IntPtr idblock;
		double countchild = 0;
        SHNLineTypes currentlinetype;
        static public IntPtr[] linetypesID = new IntPtr[3];
        #endregion

        #region Properties
        //[Browsable(false)]
        public String Name
        {
            get { return name; }
            set { name = value; }
        }

        public List<INetElement> Parents
        {
            get { return parents; }
            set { parents = value; }
        }

        public String Interval
        {
            get { return interval; }
            set { interval = value; }
        }

        public Color Color
        {
            get { return c; }
            set { c = value; }
        }

        public Double MaxLength { get; set; }

        public String Cost { get; set; }

        [Browsable(false)]
        public String InName
        {
            get { return I.Name; }
        }

        [Browsable(false)]
        public String OutName
        {
            get { return O.Name; }
        }

        public Double Weight
        {
            get { return weight; }
            set { weight = value; }
        }

        public Int32 Capacity
        {
            get;
            set;
        }

        [Browsable(false)]
        public INode GetIn
        {
            get { return I; }
            set { I = value; }
        }

        [Browsable(false)]
        public INode GetOut
        {
            get { return O; }
            set { O = value; }
        }

        public Boolean Select
        {
            get { return s; }
            set { s = value; }
        }

        public double Width
        {
            get { return width; }
            set { width = value; }
        }

        /*[Browsable(false)]
        public IntPtr Idtable
        {
            get { return idtable; }
            set { idtable = value; }
        }

        [Browsable(false)]
        public IntPtr Idblock
        {
            get { return idblock; }
            set { idblock = value; }
        }*/

        public SHNLineTypes LineType
        {
            get { return currentlinetype; }
            set { currentlinetype = value; }
        }

        public Double Length
        {
            get
            {
                if (parents == null) return Math.Sqrt((I.X - O.X) * (I.X - O.X) + (I.Y - O.Y) * (I.Y - O.Y));
                if (parents.Count == 0) return Math.Sqrt((I.X - O.X) * (I.X - O.X) + (I.Y - O.Y) * (I.Y - O.Y));
                Double l = 0;
                foreach (INetElement e in parents)
                {
                    Edge edge = e as Edge;
                    if (edge != null)
                        l += edge.Length;
                }
                if (l == 0) return Math.Sqrt((I.X - O.X) * (I.X - O.X) + (I.Y - O.Y) * (I.Y - O.Y));
                return l;
            }
        }

		public Double CountChild
		{
			get { return countchild; }
			set { countchild = value; }
		}

        #endregion

        #region Constructors

        public Edge()
        {
        }

        /// <summary>
        /// Create new edge by same parameters
        /// </summary>
        /// <param name="In">reference on node, cannot be nul</param>
        /// <param name="Out">reference on node, cannot be nul</param>
        /// <param name="w">width</param>
        /// <param name="lt">Line Type</param>
        /// <exception cref="ArgumentException">Throw when in or out = null</exception>
        public Edge(Node In, Node Out, Single w, SHNLineTypes lt)
        {
            if (In == null) throw new System.ArgumentException("Parameter cannot be null","In");
            if (Out == null) throw new System.ArgumentException("Parameter cannot be null", "Out");
            I = In;
            O = Out;
            weight = 1;
            interval = "";
            width = w;
            LineType = lt;
        }

        /// <summary>
        /// Create new edge by same parameters
        /// </summary>
        /// <param name="In">reference on  <see cref="Node"/>, cannot be nul</param>
        /// <param name="Out">reference on  <see cref="Node"/>, cannot be nul</param>
        /// <param name="w">width</param>
        /// <param name="color">color</param>
        /// <param name="lt">Line Type</param>
        /// <exception cref="ArgumentException">Throw when in or out = null</exception>
        public Edge(Node In, Node Out, Single w, Color color, SHNLineTypes lt)
        {
            if (In == null) throw new System.ArgumentException("Parameter cannot be null", "In");
            if (Out == null) throw new System.ArgumentException("Parameter cannot be null", "Out");
            I = In;
            O = Out;
            weight = 1;
            interval = "";
            width = w;
            c = color;
            LineType = lt;
        }

        /// <summary>
        /// Create new edge by <see cref="SHNXml.Edge edge"/>
        /// </summary>
        /// <param name="In">reference on <see cref="Node"/>, cannot be nul</param>
        /// <param name="Out">reference on  <see cref="Node"/>, cannot be nul</param>
        /// <param name="edge">reference on  <see cref="SHNXml.Edge edge"/></param>
        /// <exception cref="ArgumentException">Throw parameters = null</exception>
        public Edge(SHNXml.Edge edge, INode In, INode Out)
        {
            if (In == null) throw new System.ArgumentException("Parameter cannot be null", "In");
            if (Out == null) throw new System.ArgumentException("Parameter cannot be null", "Out");
            if (edge == null) throw new System.ArgumentException("Parameter cannot be null", "edge");
            I = In;
            O = Out;
            interval = edge.Interval;
            name = edge.Name;
            weight = edge.Weight;
            c = Color.FromName(edge.Color);
            width = edge.Width;
            Capacity = edge.Capacity;
            LineType = (SHNLineTypes)edge.LineType;
        }

        #endregion 

        #region Methods

        public virtual void AddParent(INetElement parent)
        {
            parents.Add(parent);
        }

        public void SetNumOfChild(double i)
		{
			countchild = i;
		}

		public void IncrementNumOfChild()
		{
			countchild ++;
		}

		public void DecrementNumOfChild()
		{
			countchild--;
		}

        private Single sgn(Single s)
        {
            if (s == 0)
                return 0;
            if (s >= 0)
                return 1;
            return -1;
        }
        
        public Object Clone()
        {
            Edge edge = new Edge();
            edge.Capacity = this.Capacity;
            edge.Color = this.Color;
			edge.Cost = this.Cost;
			edge.MaxLength = this.MaxLength;
            edge.Interval = this.Interval;
            edge.Name = this.Name;
			edge.LineType = this.LineType;
            edge.Select = this.Select;
            edge.Weight = this.Weight;
            edge.Width = this.Width;
			edge.Parents = new List<INetElement>();
			for (int i = 0; i < this.Parents.Count; i++)
				edge.Parents.Add(this.parents[i] as INetElement);
			edge.GetIn = this.GetIn;
			edge.GetOut = this.GetOut;
            return edge;
        }
        
        public Boolean IsEnable(Int32 i)
        {
            try
            {
                String[] str = interval.Split('-');
                if ((Convert.ToInt32(str[0]) > i) | (Convert.ToInt32(str[1]) <= i))
                    return false;
            }
            catch
            {
                return true;
            }
            finally
            {

            }
            return true;
        }

        public IntPtr GetLineTypeID()
        {
            return linetypesID[(int)LineType];
        }

        #endregion
    }
    public interface ISHyperNet : INetElement
    {
        #region Properties
        /// <summary>
        /// set/get parents' element
        /// </summary>
        ISHyperNet Parent { get; set; }

        String Name { get; set; }

        Int32 CountNode { get; }

        Int32 CountEdge { get; }

        Int32 CountNestNet { get; }

		NetConfig CurrentNetConfig { get; set; }

		Boolean Enable { get; set; }

        Int32[,] MI { get; }

		IEdge [,] AdjacencyMatrix { get; }	

		List<Int32[,]> ME { get; }


        #endregion

        #region Methods

        void AddNode(INode node);

        void AddEdge(IEdge edge);

        void AddNestNet(ISHyperNet net);

        List<IEdge> DeleteNode(INode node);

        void DeleteEdge(IEdge edge);

        void DeleteNestNet(Int32 index);

		void DeleteNestNet(ISHyperNet shn);

        INode GetNode(Int32 index);

        IEdge GetEdge(Int32 index);

        //INetElement GetElementById(IntPtr obj_id);

		ISHyperNet GetNestNet(Int32 i);

		String NodeSetDefaultName();

		String EdgeSetDefaultName();

        Int32 Find(IEdge Edge);

        //INode FindNode(IntPtr id);
        
        Double Cost();

        void ApplyNetConfig(SHN.NetConfig iNC);

        Edge GetEdgeByNodes(SHN.Node node1, SHN.Node node2);

        Boolean Visible { get; set; }

        SHyperNet GetNetByName(SHyperNet t, string name);
        
        #endregion
    }

    /// <summary> 
    /// Class of S-Hypernet.
    /// </summary> 
    public class SHyperNet : ISHyperNet
    {
        #region Attributes
        List<ISHyperNet> nestNets;
        Boolean s;
        List<INode> nodes;        //Список вершин
        List<IEdge> edges;        //Список ребер
        List<String> node_holes = new List<string>();		//имена удаленных нодов для восстановления
        List<String> edge_holes = new List<string>();		//имена удаленных нодов для восстановления
        String name;          //Имя
        Byte p;               //Приоретет
        Int32[,] mi;	//Матрица инцедентности
		List<Int32[,]> me; //Лист матриц для детей у edge
        Boolean En = true;           //Enable
        SHyperNet parent;
        Boolean visible = true;
        IEdge[,] aMatrix;
        Double[,] weightMatrix;
        Boolean isWeightMatrixNeedRecalc = true;
        Boolean isIncidentMatrixNeedRecalc = true;
        Boolean isAdjacencyMatrixNeedRecalc = true;
		Boolean isEdgeMatrixNeedRecalc = true;
        NetConfig netconf = new NetConfig();       
        #endregion
        #region Properties

        public List<ISHyperNet> NestNets
        {
            get { return nestNets; }
        }

        public Int32 CountNode { get { return nodes.Count; } }

        public Int32 CountEdge { get { return edges.Count; } }

        public Int32 CountNestNet { get { return nestNets.Count; } }

        /// <summary>
        /// get incidence matrix
        /// </summary>
        [Browsable(false)]
		public List<Int32[,]> ME
        {
            get
            {
                if (isEdgeMatrixNeedRecalc)
                {
                    CreateME();
                    isEdgeMatrixNeedRecalc = false;
                }
                return me;
            }
        }

        [Browsable(false)]
		public Int32[,] MI
		{
			get
			{
				if (isIncidentMatrixNeedRecalc)
				{
					CreateMI();
					isIncidentMatrixNeedRecalc = false;
				}
				return mi;
			}
		}

        /// <summary>
        /// Adjacency matrix, where cell [i][j] is adress of edge that connects i & j nodes
        /// </summary>
        [Browsable(false)]
        public IEdge[,] AdjacencyMatrix
        {
			get
			{
				if (isAdjacencyMatrixNeedRecalc)
				{
					CreateMA();
					isAdjacencyMatrixNeedRecalc = false;
				}
				return aMatrix;
			}                   
        }

        /// <summary>
        /// get/set parent
        /// </summary>
        public ISHyperNet Parent
        {
            get { return parent; }
            set { parent = value as SHyperNet; }
        }

        /// <summary>
        /// get/set name
        /// </summary>
        public String Name
        {
            get { return name; }
            set { name = value; }
        }

        public Byte Priority
        {
            get { return p; }
            set { p = value; }
        }

        public Boolean Enable
        {
            get { return En; }
            set { En = value; }
        }

        /// <summary>
        /// true if this net is selected
        /// </summary>
        public Boolean Select { get { return s; } set { s = value; } }

        public Boolean Visible { get { return visible; } set { visible = value; } }

        public NetConfig CurrentNetConfig
        {
            get { return netconf; }
            set { netconf = value; }
        }

        public string NodeHoles
        {
            get
            {
                if (node_holes.Count != 0)
                    return node_holes[0];
                else
                    return null;
            }
            set
            {
				if (!value.Contains("mini"))
					node_holes.Add(value);
            }
        }

        public string EdgeHoles
        {
            get
            {
                if (edge_holes.Count != 0)
                    return edge_holes[0];
                else
                    return null;
            }
            set
            {
                edge_holes.Add(value);
            }
        }

        [Browsable(false)]
        public Double[,] WeightMatrix
        {
            get
            {
                if (isWeightMatrixNeedRecalc)
                {
                    double[,] ret = new double[nodes.Count, nodes.Count];

                    for (int i = 0; i < nodes.Count; i++)
                        for (int j = 0; j < nodes.Count; j++)
                            ret[i, j] = double.PositiveInfinity;

                    foreach (IEdge edge in edges)
                    {
                        int x = Find(edge.GetIn);
                        int y = Find(edge.GetOut);
                        double val = edge.Length * edge.Weight;
                        ret[x, y] = val;
                        ret[y, x] = val;
                    }
                    weightMatrix = ret;
                    isWeightMatrixNeedRecalc = false;
                }
                return weightMatrix;
            }
        }

        #endregion

        #region Constructors

        public SHyperNet()
        {
            nodes = new List<INode>();
            edges = new List<IEdge>();
            nestNets = new List<ISHyperNet>();
            FirstSetNetConfig();
        }

        /// <summary>
        /// Create new object by <see cref="SHNXml.SHyperNet shn"/>
        /// </summary>
        /// <param name="shn">Reference on <see cref="SHNXml.SHyperNet shn"/>, cannot be null</param>
        /// <param name="parent">Reference on <see cref="SHyperNet"/></param>
        /// <exception cref="ArgumentException">Throw when shn = null </exception>
        public SHyperNet(SHNXml.SHyperNet shn, SHyperNet parent)
        {
            if (shn == null) throw new System.ArgumentException("Parameter cannot be null", "shn");
            name = shn.Name;			
            this.parent = parent;
            nodes = new List<INode>();
            for (Int32 i = 0; i < shn.Nodes.Count; i++)
            {
                try
                {
                    Node node = new Node(shn.Nodes[i]);
                    if (parent != null)
                        node.Parent = this.parent.FindElementByName(shn.Nodes[i].Parent);
                    node.ChildEdgelist = new List<Edge>();
                    nodes.Add(node);
                }
                catch (System.ArgumentException e)
                {

                }
            }

            edges = new List<IEdge>();
            for (Int32 i = 0; i < shn.Edges.Count; i++)
            {
                try
                {
                Edge edge = new Edge(shn.Edges[i], FindNode(shn.Edges[i].InName), FindNode(shn.Edges[i].OutName));

                if (parent != null)
                {
                    List<INetElement> parents = new List<INetElement>();
                    String[] str = shn.Edges[i].Parents.Split(';');
                    foreach (String s in str)
                    {

                        INetElement t = parent.FindElementByName(s);
                        if (t != null)
                        {
                            try
                            {
                                edge.AddParent(t);
                            }
                            catch (ArgumentException ex)
                            {

                            }
                               
                        }
                    }
                   
                }
                edges.Add(edge);
                }
                catch (System.ArgumentException e)
                {

                }
            }

            nestNets = new List<ISHyperNet>();
            for (Int32 i = 0; i < shn.NestNet.Count; i++)
            {
                try
                {
                    nestNets.Add(new SHyperNet(shn.NestNet[i], this));
                }
                catch (System.ArgumentException e) { }
            }
			for (Int32 i = 0; i < shn.Nodes.Count; i++)
			{
				Node node = this.GetNode(i) as Node;
				String[] st = shn.Nodes[i].Children.Split(';');
				foreach (String s in st)
				{
					INetElement t;
					for (int j = 0; j < shn.NestNet.Count; j++)
					{
						try
						{
							t = (this.GetNestNet(j) as SHyperNet).FindElementByName(s);
							if (t != null)
								node.ChildEdgelist.Add(t as Edge);
						}
						catch { node.ChildEdgelist.Clear(); }
					}
				}
			}

			///Net Configuration
			try
			{
				netconf.EdgeColor = Color.FromName(shn.netconf.edge_color);
				netconf.EdgeLinetype = shn.netconf.edge_linetype;
				netconf.EdgeWidth = shn.netconf.edge_width;
				netconf.NodeColor = Color.FromName(shn.netconf.node_color);
				netconf.NodeLinetype = shn.netconf.node_linetype;
				netconf.NodeRadius = shn.netconf.node_radius;
				netconf.EdgeWeight = shn.netconf.edge_weight;
			}
			catch
			{
				FirstSetNetConfig();
			}
        }

        #endregion

        #region Methods
      
        public virtual Object Clone()
        {
            SHyperNet newnet = this.Clone(null, null, null) as SHyperNet;
            return newnet;
        }

        // вы тут нихрена не поймете земные твари даже не пытайтесь, тут идет запоминание и сопоставление
		private Object Clone(SHyperNet parent, Dictionary<String, int> parnodes, Dictionary<String, int> paredges)
		{
			SHyperNet newnet = new SHyperNet();
			newnet.CurrentNetConfig.EdgeColor = this.CurrentNetConfig.EdgeColor;
			newnet.CurrentNetConfig.EdgeWidth = this.CurrentNetConfig.EdgeWidth;
			newnet.CurrentNetConfig.NodeColor = this.CurrentNetConfig.NodeColor;
			newnet.CurrentNetConfig.NodeRadius = this.CurrentNetConfig.NodeRadius;
			newnet.Enable = this.Enable;
			newnet.Name = this.Name;
			newnet.Select = this.Select;
			newnet.Visible = this.Visible;
			Dictionary<String, int> nodeids = new Dictionary<String, int>();
			Dictionary<String, int> edgeids = new Dictionary<String, int>();
			int a;
			for (int i = 0; i < this.nodes.Count; i++)
			{
				newnet.nodes.Add(this.nodes[i].Clone() as Node);
				nodeids.Add(this.nodes[i].Name, i);
				if (parnodes != null)
				{
					parnodes.TryGetValue((this.nodes[i].Parent as Node).Name, out a);
					newnet.nodes[i].Parent = parent.nodes[a];
				}
			}
			for (int i = 0; i < this.edges.Count; i++)
			{
				newnet.edges.Add(this.edges[i].Clone() as Edge);
				edgeids.Add(this.edges[i].Name, i);
				nodeids.TryGetValue(this.edges[i].GetIn.Name, out a);
				newnet.edges[i].GetIn = newnet.nodes[a];
				nodeids.TryGetValue(this.edges[i].GetOut.Name, out a);
				newnet.edges[i].GetOut = newnet.nodes[a];
				/*if (paredges != null)
				{
					if (this.edges[i].Parents != null)
						for (int j = 0; j < this.edges[i].Parents.Count; j++)
						{
							paredges.TryGetValue((this.edges[i].Parents[j] as Edge).Name, out  a);
							newnet.edges[i].Parents.Add(parent.edges[a]);
						}
				}*/
			}
			newnet.parent = parent;
			//Net configurations
			newnet.netconf.EdgeColor = this.netconf.EdgeColor;
			newnet.netconf.EdgeLinetype = this.netconf.EdgeLinetype;
			newnet.netconf.EdgeWeight = this.netconf.EdgeWeight;
			newnet.netconf.EdgeWidth = this.netconf.EdgeWidth;
			newnet.netconf.NodeColor = this.netconf.NodeColor;
			newnet.netconf.NodeLinetype = this.netconf.NodeLinetype;
			newnet.netconf.NodeRadius = this.netconf.NodeRadius;
			newnet.nestNets = new List<ISHyperNet>();
			if (this.NestNets != null && this.nestNets.Count > 0)
			{

				for (int i = 0; i < this.NestNets.Count; i++)
				{
					newnet.NestNets.Add((this.NestNets[i] as SHyperNet).Clone(newnet, nodeids, edgeids) as SHyperNet);
				}

			}
			return newnet;
		}

        #region GetsAnyElement
        /// <summary>
        /// Gets node number i
        /// </summary>
        /// <param name="i">index of node</param>
        /// <exception cref="System.ArgumentException">Thrown when index is out of range </exception>
        /// <returns>reference of <see cref="INode"/></returns>
        public INode GetNode(Int32 i)
        {
            try
            {
                return nodes[i];
            }
            catch (System.IndexOutOfRangeException e)
            {
                throw new System.ArgumentException("Index is out of range", "i", e);
            }
        }
        
        /// <summary>
        /// Gets edge number i
        /// </summary>
        /// <param name="i">index of edge</param>
        /// <exception cref="System.ArgumentException">Thrown when index is out of range </exception>
        /// <returns>reference of <see cref="IEdgee"/></returns>
        public IEdge GetEdge(Int32 i)
        {
			try
			{
				return edges[i];
			}
			catch (System.IndexOutOfRangeException e)
			{
				throw new System.ArgumentException("Index is out of range", "i", e);
			}
        }

        /// <summary>
        /// Gets nested net
        /// </summary>
        /// <param name="i">index of net</param>
        /// <exception cref="System.ArgumentException">Thrown when index is out of range </exception>
        /// <returns>reference of <see cref="ISHyperNet"/></returns>
        public ISHyperNet GetNestNet(Int32 i)
        {
            try
            {
                return nestNets[i];
            }
            catch (System.IndexOutOfRangeException e)
            {
                throw new System.ArgumentException("Index is out of range", "i", e);
            }
        }

        private void Swap(Int32 i, Int32 j)
        {
            INode temp;
            temp = GetNode(i);
            nodes[i] = nodes[j];
            nodes[j] = temp;
        }

        /// <summary>
        /// чья то быдло функция. Заебали комменты не писать. И почему она не static?!
        /// </summary>
        /// <param name="t"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public SHyperNet GetNetByName(SHyperNet t, string name)
        {
            if (t.Name == name)
                return t;
            for (int i = 0; i < t.NestNets.Count; i++)
            {
                if (GetNetByName(t.NestNets[i] as SHyperNet, name) == null)
                    continue;
                else
                    return GetNetByName(t.NestNets[i] as SHyperNet, name);
            }
            return null;
        }

        public List<int> GetIncidentEdgesExceptOne(int nodeNum, int exceptionEdge)
        {
            List<int> ret = new List<int>();
            int[,] matr = MI;
            for (int i = 0; i < edges.Count; i++)
            {
                int incident = matr[nodeNum, i];
                if (incident != 0 && i != exceptionEdge)
                    ret.Add(i);
            }
            return ret;
        }

        public int GetIncidentNodeExceptOne(int edgeNum, int exceptionNode)
        {
            int[,] matr = MI;
            int ret = -1;
            for (int i = 0; i < nodes.Count; i++)
            {
                int incident = matr[i, edgeNum];
                if (incident != 0 && exceptionNode != i)
                    return i;
            }
            return ret;
        }

        /// <summary>
        /// Gets edge, which incident node1 & node2 
        /// </summary>
        /// <param name="node1"></param>
        /// <param name="node2"></param>
        /// <exception cref="ArgumentException">Throw when node1 or node2 not find in list</exception>
        public Edge GetEdgeByNodes(Node node1, Node node2)
        {
            int index1 = this.Find(node1);
            int index2 = this.Find(node2);
            if (index1 == -1)
                throw new System.ArgumentException("Node1 not find in list");
			if (index2 == -1)
				throw new System.ArgumentException("Node2 not find in list");
            int[,] s = MI;
            int buf = -1;
            for (int i = 0; i < s.GetLength(1); i++)
                if (Math.Abs(s[index1, i]) == 1 && Math.Abs(s[index2, i]) == 1)
                {
                    buf = i;
                    break;
                }
            if (buf != -1)
                return (this.GetEdge(buf) as Edge);
            else
                return null;
        }

        /// <summary>
        /// Gets node by 2 edges
        /// </summary>
        /// <param name="edge1"></param>
        /// <param name="edge2"></param>
        /// <exception cref="ArgumentException">Throw when edge1 or edge2 is null</exception>
        /// <returns></returns>
        public Node GetNodeByEdges(Edge edge1, Edge edge2)
        {
            if (edge1 == null)
                throw new System.ArgumentException("Parameter cannot be null", "edge1");
            if(edge2 == null)
                throw new System.ArgumentException("Parameter cannot be null", "edge2");
            if (edge1.GetIn == edge2.GetIn || edge1.GetIn == edge2.GetOut)
                return (Node)edge1.GetIn;
            if (edge1.GetOut == edge2.GetOut || edge1.GetOut == edge2.GetOut)
                return (Node)edge1.GetOut;
            return null;
        }
        #endregion

        /// <summary>
        /// Shorted node's list
        /// </summary>
        public virtual void Short()
        {
            Boolean f = true;
            while (f)
            {
                f = false;
                for (Int32 i = 0; i < nodes.Count - 1; i++)
                    if (GetNode(i).Priority < nodes[i + 1].Priority)
                    {
                        Swap(i, i + 1);
                        f = true;
                    }
            }
        }
        
        public void PrintMI(String filename)
        {            
            using (StreamWriter f = new StreamWriter(filename))
            {
                Int32[,] s = MI;
                for (Int32 i = 0; i < nodes.Count; i++)
                {
                    for (Int32 j = 0; j < edges.Count; j++)
                    {
                        f.Write(s[i, j]);
                        f.Write(' ');
                    }
                    f.Write("\n");
                }
            }
        }

		public void PrintME(String filename)
		{
            using (StreamWriter f = new StreamWriter(filename))
            {
                for (int l = 0; l < ME.Count; l++)
                {
                    Int32[,] s = ME[l];
                    for (int i = 0; i < s.GetLength(0); i++)
                    {
                        for (int j = 0; j < s.GetLength(1); j++)
                        {
                            f.Write(s[i, j]);
                            f.Write(' ');
                        }
                        f.WriteLine();
                    }
                    f.WriteLine();
                    f.WriteLine();
                }
            }
		}

		public void PrintMA(String filename)
		{
            using (StreamWriter f = new StreamWriter(filename))
            {
                IEdge[,] s = AdjacencyMatrix;
                for (Int32 i = 0; i < nodes.Count; i++)
                {
                    for (Int32 j = 0; j < nodes.Count; j++)
                    {
                        try { f.Write(s[i, j].Name + " "); }
                        catch { f.Write("null "); }
                        f.Write(' ');
                    }
                    f.WriteLine();
                }
            }
		}

        /// <summary>
        /// Apply cofiguration for this net <see cref="NetConfig"/>
        /// </summary>
        /// <exception cref="System.ArgumentNullException">Thrown when argument iNC is null </exception>
        /// <param name="iNC">cofiguration for apply</param>       
        public void ApplyNetConfig(NetConfig iNC)
        {
            if (iNC == null)
                throw new System.ArgumentNullException("iNC");
            for (Int32 i = 0; i < nodes.Count; i++)
            {
                GetNode(i).Radius = iNC.NodeRadius;
                GetNode(i).Color = iNC.NodeColor;
                GetNode(i).LineType = iNC.NodeLinetype;
            }
            for (Int32 i = 0; i < edges.Count; i++)
            {
                GetEdge(i).Width = iNC.EdgeWidth;
                GetEdge(i).Color = iNC.EdgeColor;
                GetEdge(i).LineType = iNC.EdgeLinetype;
                //GetEdge(i).Weight = iNC.EdgeWeight; - это не надо по идее
            }


        }

        private void FirstSetNetConfig()
        {
            netconf = new NetConfig();
            netconf.NodeColor = System.Drawing.Color.White;
            netconf.NodeRadius = 60;
			netconf.NodeLinetype = SHNLineTypes.SHN_Straight;
			netconf.EdgeLinetype = SHNLineTypes.SHN_BigDash;
            netconf.EdgeColor = System.Drawing.Color.White;
            netconf.EdgeWidth = 30;
			netconf.EdgeWeight = 10;
        }

        /// <summary>
        /// Find element by name 
        /// </summary>
        /// <param name="name">Element's name</param>
        /// <returns>reference of <see cref="INetElement"/></returns>
        public INetElement FindElementByName(String name)
        {
            INetElement el = FindNode(name);
            if (el == null) el = FindEdge(name);
            return el;
        }        
        
        private void CreateMI()//Составление матрицы инцедентности
        {
            mi = new Int32[nodes.Count,edges.Count];
            for (Int32 i = 0; i < edges.Count; i++)
            {
                mi[Find(GetEdge(i).GetOut),i] = 1;
                mi[Find(GetEdge(i).GetIn), i] = -1;
            }
        }

		private void CreateME()//Составление листа матриц для детей у edge
		{
			me = new List<int[,]>();
			int index = 0;
			for (int i = 0; i < this.NestNets.Count; i++)
			{
				int[,] temp = new int[this.CountEdge, this.nestNets[i].CountEdge];
				for (int j = 0; j < this.nestNets[i].CountEdge; j++)
				{
					
					for (int k = 0; k < this.nestNets[i].GetEdge(j).Parents.Count; k++ )
					{
						index = this.edges.IndexOf(this.nestNets[i].GetEdge(j).Parents[k] as Edge);
						if (index != -1)
							temp[index, j] = 1;
					}
					me.Add(temp);
				}
			}
		}

		private void CreateMA()
		{
			Int32 k, l;
			aMatrix = new IEdge[nodes.Count, nodes.Count];
			for (Int32 i = 0; i < edges.Count; i++)
			{
				k = Find(edges[i].GetIn);
				l = Find(edges[i].GetOut);
				aMatrix[k, l] = edges[i];
				aMatrix[l, k] = edges[i];
			}
		}

        #region Find
        public Int32 Find(INode Node)  //Поиск вершины (пригодиться в составление матрицы инцедентности)
        {
            for (Int32 i = 0; i < nodes.Count; i++)
            {
                if (Object.ReferenceEquals(Node, GetNode(i)))
                    return i;
            }
            return -1;
        }

        public Int32 Find(IEdge Edge)
        {
            return edges.IndexOf(Edge);
        }

        public INode FindNode(String Name)
        {
            for (Int32 i = 0; i < nodes.Count; i++)
                if (GetNode(i).Name == Name)
                    return GetNode(i);
            return null;
        }

        public IEdge FindEdge(String Name)
        {
            for (Int32 i = 0; i < edges.Count; i++)
                if (edges[i].Name == Name)
                    return edges[i];
            return null;
        }

        /*public INode FindNode(IntPtr id)
        {
            return nodes.Find(node =>  Dict.Get(node).ToInt64() == id.ToInt64());
        }*/
        #endregion

        #region AddAnyElements
        /// <summary>
        /// Adds a node to the node's list
        /// </summary>
        /// <param name="node"></param>
        /// <exception cref="System.ArgumentNullException">Thrown when argument "node" is null </exception>
        public void AddNode(INode node)
        {
            if (node == null)
                throw new System.ArgumentNullException("node");
            isIncidentMatrixNeedRecalc = true;
            isWeightMatrixNeedRecalc = true;
            isIncidentMatrixNeedRecalc = true;
            nodes.Add(node);
        }

        /// <summary>
        /// Adds an edge to the edge's list
        /// </summary>
        /// <param name="node"></param>
        /// <exception cref="System.ArgumentNullException">Thrown when argument "edge" is null </exception>
        public void AddEdge(IEdge edge)
        {
            if (edge == null)
                throw new System.ArgumentNullException("edge");
            isIncidentMatrixNeedRecalc = true;
            isWeightMatrixNeedRecalc = true;
            isIncidentMatrixNeedRecalc = true;
			isEdgeMatrixNeedRecalc = true;
            edges.Add(edge);
        }

        /// <summary>
        /// Adds an net to the nested net's list
        /// </summary>
        /// <param name="node"></param>
        /// <exception cref="System.ArgumentNullException">Thrown when argument "net" is null </exception>
        public void AddNestNet(ISHyperNet net)
        {
            if (net == null)
                throw new System.ArgumentNullException("net");
            nestNets.Add(net);
        }
        #endregion

        public string NodeSetDefaultName()
        {
            if (node_holes == null || node_holes.Count == 0)
                return this.Name + "_Node" + (this.CountNode + 1);
            else
            {
				String name;
				if (!NodeHoles.Contains("mini"))
				{
					name = NodeHoles;
					node_holes.RemoveAt(0);
				}
				else
				{
					node_holes.RemoveAt(0);
					name = NodeSetDefaultName();
				}
				return name;
            }
        }

		public string EdgeSetDefaultName()
		{
			if (edge_holes == null || edge_holes.Count == 0)
			{
				return this.Name + "_Edge" + (this.CountEdge + 1);
			}
			else
			{
				String name;
				if (!EdgeHoles.Contains("mini"))
				{
					name = EdgeHoles;
					edge_holes.RemoveAt(0);
				}
				else
				{
					edge_holes.RemoveAt(0);
					name = EdgeSetDefaultName();
				}
				return name;
			}
		}

        #region Delete any element
        /// <summary>
        /// Removes the first occurrence of a node from the node's list
        /// </summary>
        /// <param name="node">The node to remove from the node's list</param>
        /// <returns>List of incident edge</returns>
        public List<IEdge> DeleteNode(INode node)
        {
			isIncidentMatrixNeedRecalc = true;
			isWeightMatrixNeedRecalc = true;
			node_holes.Add(node.Name);
			isAdjacencyMatrixNeedRecalc = true;
			isEdgeMatrixNeedRecalc = true;
			node_holes.Add(node.Name);
            List<IEdge> removedEdges = new List<IEdge>();
			// блок удаления вложенных еджей
			for (int i = 0; i < this.NestNets.Count; i++)
				for (int j = 0; j < (node as Node).ChildEdgelist.Count; j++)
				{
					Edge edgebuf = (node as Node).ChildEdgelist[j];
					if ((nestNets[i] as SHyperNet).edges.IndexOf(edgebuf) != -1)
					{
						for (int k = 0 ;k<edgebuf.Parents.Count; k++)
						{
							(edgebuf.Parents[k] as Edge).DecrementNumOfChild();
						}
						(nestNets[i] as SHyperNet).edge_holes.Add(edgebuf.Name);
						removedEdges.Add(edgebuf);
						(nestNets[i] as SHyperNet).edges.Remove(edgebuf);
					}
				}
            for (int i = edges.Count - 1; i >= 0; i--)
            {
                Edge currentEdge = edges[i] as Edge;
				if (currentEdge.Parents != null)
					for (int j = 0; j < currentEdge.Parents.Count; j++ )
					{
						(currentEdge.Parents[j] as Edge).DecrementNumOfChild();
					}
				if (currentEdge.GetIn == node || currentEdge.GetOut == node)
				{
					edge_holes.Add(currentEdge.Name);
					removedEdges.Add(currentEdge);
					edges.Remove(currentEdge);
				}
            }
			IEdge[,] aMatrix = AdjacencyMatrix;
			int nodeIndex = nodes.IndexOf(node);
			for (int i = 0; i < this.nodes.Count; i++)
			{
				if(aMatrix[i,nodeIndex]!=null)
				{
					edge_holes.Add(aMatrix[i,nodeIndex].Name);
					removedEdges.Add(aMatrix[i, nodeIndex]);
					edges.Remove(aMatrix[i, nodeIndex]);
				}
				if (aMatrix[nodeIndex,i] != null)
				{
					edge_holes.Add(aMatrix[nodeIndex,i].Name);
					removedEdges.Add(aMatrix[nodeIndex,i]);
					edges.Remove(aMatrix[nodeIndex,i]);
				}
			}
            nodes.Remove(node);
            return removedEdges;
        }

        /// <summary>
        /// Removes the first occurrence of a edge from the edge's list
        /// </summary>
        /// <param name="node">The edge to remove from the edge's list</param>
        public void DeleteEdge(IEdge edge)
        {
            isWeightMatrixNeedRecalc = true;
            isIncidentMatrixNeedRecalc = true;
			isEdgeMatrixNeedRecalc = true;
            isAdjacencyMatrixNeedRecalc = true;
			edge_holes.Add(edge.Name);
            edges.Remove(edge);
        }

        /// <summary>
        /// Removes the first occurrence of a node from the node's list
        /// </summary>
        /// <param name="id">node's id</param>
        /// <returns>List of incident edge</returns>
        /*public List<IEdge> DeleteNode(IntPtr id)
        {
            isIncidentMatrixNeedRecalc = true;
            isWeightMatrixNeedRecalc = true;
            isIncidentMatrixNeedRecalc = true;
            return this.DeleteNode(nodes.Find(node => Dict.Get(node) == id));
        }*/

        /// <summary>
        /// Removes the first occurrence of a node from the nested net's list
        /// </summary>
        /// <param name="index">Net's index</param>
        /// <exception cref="System.ArgumentException">Thrown when index is out of range </exception>
        public void DeleteNestNet(Int32 index)
        {
            try
            {
                nestNets.RemoveAt(index);
            }
            catch (System.IndexOutOfRangeException e)
            {
                throw new System.ArgumentException("Index is out of range", "index", e);
            }
        }

        /// <summary>
        /// Removes the first occurrence of a node from the nested net's list
        /// </summary>
        /// <param name="shn">The net to remove from the edge's list</param>
        public void DeleteNestNet(ISHyperNet shn)
        {
            for (int i = 0; i < nestNets.Count; i++)
            {
                if (nestNets[i] == shn)
                {
                    nestNets.RemoveAt(i);
                    return;
                }
            }
        }
        #endregion

        public int[,] GetKirchhoffMatrix()
        {
            int[,] ret = new int[nodes.Count, nodes.Count];
            for (int i = 0; i < edges.Count; i++)
            {
                int incoming = Find(edges[i].GetIn);
                int outcoming = Find(edges[i].GetOut);
                ret[incoming, incoming]++;
                ret[outcoming, outcoming]++;
                ret[incoming, outcoming] = -1;
                ret[outcoming, incoming] = -1;
            }
            return ret;
        }

        public string GetMIAsString()
        {
            int[,] matr = this.MI;
            string ret = String.Empty;
            for (int j = 0; j < edges.Count; j++)
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    ret += matr[i,j] + " ";
                }
                ret += "\n";
            }
            return ret;
        }

        public List<int> GetIncidentEdges(int nodeNumber)
        {
            List<int> ret = new List<int>();
            int[,] matr = MI;
            for (int i = 0; i < edges.Count; i++)
            {
                if (matr[nodeNumber,i] != 0)
                {
                    ret.Add(i);
                }
            }
            return ret;
        }

        public void GetIncidentNodesNumbers(int edgeNumber, out int node1, out int node2)
        {
            int[,] matr = MI;
            node1 = 0;
            node2 = 0;
            int count = 0;
            for (int i = 0; i < nodes.Count && count < 2; i++)
            {
                if (matr[i,edgeNumber] != 0)
                {
                    count++;
                    if (count == 1)
                        node1 = i;
                    else if (count == 2)
                        node2 = i;
                }
            }
        }

        public bool CheckForSkeleton(IEnumerable<int> edgesInSkeleton)
        {
            int[,] matr = MI;
            int node1, node2;
            int[] color = new int[nodes.Count];
            List<object> palette = new List<object>(5);
            foreach (int edgeNum in edgesInSkeleton)
            {
                GetIncidentNodesNumbers(edgeNum, out node1, out node2);
                if (color[node1] == 0 && color[node2] == 0)
                {
                    object newColor = new object();
                    palette.Add(newColor);
                    color[node1] = palette.Count;
                    color[node2] = palette.Count;
                }
                else if (color[node1] == 0 && color[node2] != 0)
                {
                    color[node1] = color[node2];
                }
                else if (color[node1] != 0 && color[node2] == 0)
                {
                    color[node2] = color[node1];
                }
                else if (palette[color[node1] - 1] == palette[color[node2] - 1])
                {
                    return false;
                }
                else if (color[node1] != 0 && color[node2] != 0)
                {
                    palette[color[node1] - 1] = palette[color[node2] - 1];
                }
            }
            object first = palette[0];
            foreach (object c in palette)
            {
                if (c != first)
                    return false;
            }
            return true;
        }

        public long GetNumberOfSkelentons()
        {
            int[,] matr = GetKirchhoffMatrix();
            double[,] doubleMatr = new double[nodes.Count - 1, nodes.Count - 1];
            for (int i = 1; i < nodes.Count; i++)
                for (int j = 1; j < nodes.Count; j++)
                    doubleMatr[i - 1, j - 1] = matr[i, j];
            double det = MatrixLibrary.Matrix.Det(doubleMatr);
            return (long)det;
        }

        public override string ToString()
        {
            return NetAsString(this, 0);
        }        

        private static string NetAsString(ISHyperNet net, int offset)
        {
            string ret = String.Empty;
            for (int i = 0; i < offset; i++)
                ret += " ";
            SHyperNet hyperNet = net as SHyperNet;
            if (net != null)
            {
                ret += String.Format("Hyper Net: nest nets count: {0}, edges count: {1}, nodes count: {2}\n", hyperNet.nestNets.Count
                    , hyperNet.edges.Count, hyperNet.nodes.Count);
                if (hyperNet.nestNets.Count != 0)
                {
                    offset += 4;
                    foreach (ISHyperNet inet in hyperNet.nestNets)
                        ret += NetAsString(inet, offset);

                    offset -= 4;
                }
            }
            return ret;
        }

        public List<int> DepthFirstSearch(int node1, int node2, Predicate<int> edgesPredicate)
        {
            //List<int> ret = new List<int>(nodes.Count / 2);
            Stack<int> nodesToVisit = new Stack<int>(nodes.Count / 2);
            Stack<int> edgesInStack = new Stack<int>(nodes.Count / 2);
            int[,] matr = MI;
            int currentNode = node2;
            int[] visitedNodes = new int[nodes.Count];
            nodesToVisit.Push(node2);
            visitedNodes[node2] = 1;
            try
            {
                while (nodesToVisit.Count >= 1)
                {
                    currentNode = nodesToVisit.Pop();
                    if (currentNode == -1)
                        return null;
                    bool flag = false;
                    for (int i = 0; i < edges.Count; i++)
                    {
                        if (matr[currentNode,i] != 0)
                        {
                            if (edgesPredicate != null)
                            {
                                if(!edgesPredicate(i))
                                    continue;
                            }
                            for (int j = 0; j < nodes.Count; j++)
                            {
                                if (matr[j,i] != 0 && j != currentNode)
                                {
                                    if (visitedNodes[j] == 0)
                                    {
                                        edgesInStack.Push(i);
                                        nodesToVisit.Push(currentNode);
                                        nodesToVisit.Push(j);
                                        visitedNodes[j] = 1;
                                        flag = true;
                                    }
                                    break;
                                }
                            }
                        }
                        if (flag)
                            break;
                    }
                    if (!flag)
                        edgesInStack.Pop();
                    else
                    {
                        if (visitedNodes[node1] != 0)
                        {
                            return new List<int>(edgesInStack);
                        }
                    }

                }
            }
            catch (InvalidOperationException)
            {
                return null;
            }
            return null;
        }

        public List<int> GetRandomSkeleton()
        {
            SHyperNet hyperNet = this;
            int unmarkedNodesCount = hyperNet.CountNode;
            List<int> reachableEdges = new List<int>();
            List<int> skeleton = new List<int>();
            int[] markedNodes = new int[hyperNet.CountNode];
            int[,] MI = hyperNet.MI;
            int rand = SHNConstants.random.Next(hyperNet.CountEdge), count = 0, incident = 0, markedNodesCount = 2;
            skeleton.Add(rand);
            for (int i = 0; i < hyperNet.CountNode && count < 2; i++)
            {
                incident = MI[i,rand];
                if (incident != 0)
                {
                    count++;
                    markedNodes[i] = 1;
                    for (int j = 0; j < hyperNet.CountEdge; j++)
                    {
                        incident = MI[i,j];
                        if (incident != 0 && j != rand)
                        {
                            reachableEdges.Add(j);
                        }
                    }
                }
            }
            do
            {
                rand = SHNConstants.random.Next(reachableEdges.Count);
                count = 0;
                int edgeNumToAdd = reachableEdges[rand];
                skeleton.Add(edgeNumToAdd);
                reachableEdges.Remove(edgeNumToAdd);
                for (int i = 0; i < hyperNet.CountNode && count < 2; i++)
                {
                    incident = MI[i,edgeNumToAdd];
                    if (incident != 0)
                    {
                        count++;
                        if (markedNodes[i] == 0)
                        {
                            markedNodes[i] = 1;
                            markedNodesCount++;
                            for (int j = 0; j < hyperNet.CountEdge; j++)
                            {
                                incident = MI[i,j];
                                if (incident != 0 && j != edgeNumToAdd)
                                {
                                    for (int k = 0; k < hyperNet.CountNode; k++)
                                    {
                                        incident = MI[k,j];
                                        if (incident != 0 && k != i)
                                        {
                                            if (markedNodes[k] == 0)
                                            {
                                                reachableEdges.Add(j);
                                                break;
                                            }
                                            else
                                            {
                                                reachableEdges.Remove(j);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            while (reachableEdges.Count > 0);
            return skeleton;
        }

        public List<List<IEdge>> DepthFirstSearchAllRoutes(int node1, int node2, Predicate<IEdge> isAppropriateEdge)
        {
            Stack<int> nodesToVisit = new Stack<int>();
            Stack<IEdge> edgesInStack = new Stack<IEdge>();
            Stack<int> prevIndex = new Stack<int>();
            nodesToVisit.Push(node2);
            prevIndex.Push(0);
            bool[] visitedNodes = new bool[nodes.Count];
            visitedNodes[node2] = true;
            IEdge[,] adjMatr = AdjacencyMatrix;
            List<List<IEdge>> routes = new List<List<IEdge>>();
            while (nodesToVisit.Count != 0)
            {
                bool flag = false;
                int currNode = nodesToVisit.Pop();
                int j = prevIndex.Pop();
                for (; j < nodes.Count; j++)
                {
                    if (visitedNodes[j])
                        continue;
                    IEdge currEdge = adjMatr[currNode, j];
                    if (currEdge != null)
                    {
                        if (isAppropriateEdge != null)
                            if (!isAppropriateEdge(currEdge))
                                continue;
                        flag = true;
                        nodesToVisit.Push(currNode);
                        nodesToVisit.Push(j);
                        edgesInStack.Push(currEdge);
                        prevIndex.Push(j + 1);
                        prevIndex.Push(0);
                        visitedNodes[j] = true;
                    }
                    if (flag)
                        break;
                    
                }
                if (flag)
                {
                    if (j == node1)
                    {
                        visitedNodes[j] = false;
                        routes.Add(new List<IEdge>(edgesInStack));
                        edgesInStack.Pop();
                        nodesToVisit.Pop();
                        prevIndex.Pop();
                    }
                }
                else
                {
                    if (edgesInStack.Count == 0)
                        return routes;
                    edgesInStack.Pop();
                    visitedNodes[currNode] = false;
                }
            }
            return routes;
        }

        public void SortEdgesByLength()
        {
            edges.Sort((edge1, edge2) => edge1.Length.CompareTo(edge2.Length));
            isAdjacencyMatrixNeedRecalc = true;
            isEdgeMatrixNeedRecalc = true;
            isIncidentMatrixNeedRecalc = true;
        }

        public List<INetElement> GetChilds(INetElement parent)
        {
            List<INetElement> ret = new List<INetElement>();
            foreach (ISHyperNet nestNet in nestNets)
            {
                for (int i = 0; i < nestNet.CountEdge; i++)
                    if (nestNet.GetEdge(i).Parents.Contains(parent))
                        ret.Add(nestNet.GetEdge(i));
                for (int i = 0; i < nestNet.CountNode; i++)
                    if (nestNet.GetNode(i).Parent == parent)
                        ret.Add(nestNet.GetNode(i));
                
            }
            return ret;
        }

        public Double Cost()
        {
            Double cost = 0;
            for (Int32 i = 0; i < edges.Count; i++)
                cost += edges[i].Weight * edges[i].Length;
            for (Int32 i = 0; i < nestNets.Count; i++)
                cost += nestNets[i].Cost();
            return cost;
        }

		public void DisconnectEdges()
		{
			for (int i = 0; i < CountEdge; i++)
			{
				this.GetEdge(i).Parents = new List<INetElement>();
				this.GetEdge(i).Parents.Clear();
			}
		}

        #endregion
    }

    public class IncorrectWayException : Exception
    {
        public String ContraryParameter { get; private set; }
        public IncorrectWayException()
        {
        }
        public IncorrectWayException(string message)
            : base(message)
        {
        }
        public IncorrectWayException(string message, String contraryParameter)
            : base(message)
        {
            ContraryParameter = contraryParameter;
        }

        public IncorrectWayException(string message, Exception inner)
            : base(message, inner)
        {
        }
        public IncorrectWayException(String contraryParameter, string message, Exception inner)
            : base(message, inner)
        {
            ContraryParameter = contraryParameter;
        }
    }

    public enum SHNLineTypes
    {
        SHN_BigDash,
        SHN_SmallDash,
        SHN_Straight
    }

    #region Styles
    /// <summary>
    /// Interface for Net Elements
    /// </summary>
    public interface IStyle
    {
        String Name { get; set; }
    }
    /// <summary>
    /// Nodes style class. It has basic properties for node
    /// </summary>
    public class NodeStyle : IStyle
    {
        String name;
        Color c;
        Double R;
        SHNLineTypes currentlinetype;

        public String Name
        {
            get { return name; }
            set { name = value; }
        }
        public Color Color
        {
            get { return c; }
            set { c = value; }
        }
        public Double Radius
        {
            get { return R; }
            set { R = value; }
        }
        public SHNLineTypes LineType
        {
            get { return currentlinetype; }
            set { currentlinetype = value; }
        }
    }
    public class EdgeStyle : IStyle
    {
        String name;
        double width;
        Color c;
        SHNLineTypes currentlinetype;

        public String Name
        {
            get { return name; }
            set { name = value; }
        }
        public Color Color
        {
            get { return c; }
            set { c = value; }
        }
        public Double Width
        {
            get { return width; }
            set { width = value; }
        }
        public SHNLineTypes LineType
        {
            get { return currentlinetype; }
            set { currentlinetype = value; }
        }
    }
    #endregion

}//namespace